package com.qfedu.aunt.commons.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qfedu.aunt.commons.constance.RedisConstance;
import com.qfedu.aunt.commons.exception.BusinessException;
import com.qfedu.aunt.commons.manager.RedisManager;
import com.qfedu.aunt.commons.pojo.Ad;
import com.qfedu.aunt.commons.mapper.AdMapper;
import com.qfedu.aunt.commons.result.ResponseCode;
import com.qfedu.aunt.commons.service.AdService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * <p>
 * 广告表 服务实现类
 * </p>
 *
 * @author xiaobobo
 * @since 2022-10-26
 */
@Service
public class AdServiceImpl extends ServiceImpl<AdMapper, Ad> implements AdService {

    @Autowired
    private AdMapper adMapper;

    @Autowired
    private RedisManager redisManager;

    @PostConstruct
    public void init() throws Exception {
        //提前将这个接口需要的数据 放到 缓存Redis中去
        //怎么存进去?  以什么样的数据类型存呢? 管他怎么样都要将这个数据查询出来
        initAd();
    }

    /**
     * 初始化缓存内容
     */
    private void initAd() throws Exception {
        //首先查询的是我们的广告类型有哪些
        QueryWrapper<Ad> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(" DISTINCT  ad_type ");
        //查询所有的广告类型
        List<Ad> adList = adMapper.selectList(queryWrapper);
        //通过广告类型查询我们的广告
        for (Ad ad:adList) {
            //获取广告类型
            Integer adType = ad.getAdType();
            //通过广告类型查询广告
            //执行到这里说明这个集合中没有数据 那么就要查询数据库
            QueryWrapper<Ad> queryWrapper1 = new QueryWrapper<>();
            queryWrapper.eq("ad_type", adType);
            List<Ad> adList1 = adMapper.selectList(queryWrapper1);
            //接下来需要将这个广告的数据放到 Redis中去
            //怎么放？什么数据类型?
            /**
             * 1、就是我们放进去之后 要方便取出来(效率高)
             * 2、后台改了这个数据同步要方便
             *    关于后台的数据同步 我们一般的做法是 直接删除Redis中的数据 我们是不需要去修改这个数据的
             * 3、设计：
             *   使用String类型来存储数据
             *   key：指定的默认前缀:广告类型   就是当前这个广告类型中的这个数据的JSON格式
             */
            //首先将这个广告类型是数据转换成JSON格式
            String val = JSON.toJSONString(adList1);
            //然后将这个数据存储到Redis中
            String key= RedisConstance.getAdTypePrefix()+adType;
            //接下来将这个数据存储到Redis中
            redisManager.addString(key,
                    val,
                    RedisConstance.getExpireTime(),
                    RedisConstance.getExpireTimeUnit());
        }


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<Ad> findAdsByType(Integer adType) throws Exception {
        if(null==adType){
            throw new BusinessException(ResponseCode.PARAMETER_ERROR.getCode(),
                    ResponseCode.PARAMETER_ERROR.getMessage());
        }
        //这个过后说明参数合法
        //先从缓存中获取数据
        //首先组装我们的key
        String key=RedisConstance.getAdTypePrefix()+adType;

        synchronized (this) {
            //从Redis中获取数据
            String val = (String) redisManager.getString(key);
            //判断这个数据是否为空
            if (null!=val&&"".equals(val)) {
                return null;
            }
            if(null!=val){
                //执行到这里 说明有数据
                List<Ad> adList1 = JSON.parseArray(val, Ad.class);
                if (null != adList1 && adList1.size() != 0) {
                    return adList1;
                }
            }
            //执行到这里说明这个集合中没有数据 那么就要查询数据库
            QueryWrapper<Ad> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("ad_type", adType);
            List<Ad> adList = adMapper.selectList(queryWrapper);
            //判断数据库中查询出来是否有数据
            if (null != adList && adList.size() != 0) {
                //说明数据库查询到数据出来了
                //先放到Redis中
                redisManager.addString(
                        key,
                        JSON.toJSONString(adList),
                        RedisConstance.getExpireTime(),
                        RedisConstance.getExpireTimeUnit());
                //接下来返回这个数据
                return adList;
            }
            //执行到这里：说明从MySQL没有查询到数据  没有查询到数据解决缓存穿透的问题
            //首先向Redis中写入空数据
            redisManager.addString(key,
                    "",
                    RedisConstance.getExpireTime(),
                    RedisConstance.getExpireTimeUnit());

            //接下来返回null
            return null;
        }
    }



}
